/**
 * Author(s): xuming.Wong <xuming.Wong@gmail.com>
 */

#ifndef __PQ_GameObject_H__
#define __PQ_GameObject_H__

#include "Component.h"

namespace PQEngine
{
	
	enum GameObjectType
	{
		//Root
		GAME_OBJECT_ROOT,

		//Movable
		GAME_OBJECT_EMPTY,
		GAME_OBJECT_MESH,
		GAME_OBJECT_LIGHT,
		GAME_OBJECT_CAMERA,

		//None movable
		GAME_OBJECT_TERRAIN,
	};

	class ColliderComponent;
	class RigidBodyComponent;
	class ScriptComponent;
	/*Game Object can contain one or more component for functionality.
	*/
	class GameObject
		: public Object
	{
	public:
		typedef std::map<Ogre::SceneNode*,GameObject*> MapList;
	public:
		static GameObject* get(Ogre::SceneNode* node);//search object by scene node
	public:
		GameObject(SceneObject* sceneObject,GameObjectType type);
		
		void addChild(GameObject *object);
		void removeChild(GameObject *object);

		void setParent(GameObject* parent);
		GameObject* getParent();

		int getChildrenCount();
		GameObject* getChild(int index);

		//component management.
		void addComponent(Component *component); 
		bool hasComponent(Component *component);
		bool removeComponent(Component *component);

		TransformComponent* getTransformComponent();
		MeshComponent* getMeshComponent();

		ColliderComponent* getColliderComponent()
		{

			return 0;
		}

		RigidBodyComponent* getRigidBodyComponent(){
			return 0;
		}

		ScriptComponent* getScriptComponent(){
			return 0;
		}

		bool isRigidBody(){
			return false;
		}
		//manage transform
		void setPosition(float x,float y,float z);
		void setPosition(Ogre::Vector3 position);
		void setOrientation(Ogre::Quaternion orient);
		void setScale(Ogre::Vector3 scale);

		/** Rotate the node around the Y-axis.
		*/
		virtual void yaw(const Ogre::Radian& angle, Ogre::Node::TransformSpace relativeTo = Ogre::Node::TS_LOCAL);

		   
		/** Moves the node along the Cartesian axes.
            @par
                This method moves the node by the supplied vector along the
                world Cartesian axes, i.e. along world x,y,z
            @param 
                d Vector with x,y,z values representing the translation.
            @param
                relativeTo The space which this transform is relative to.
        */
		virtual void translate(const Ogre::Vector3& d, Ogre::Node::TransformSpace relativeTo = Ogre::Node::TS_PARENT);


		void setDirection(const Ogre::Vector3& vec, Ogre::Node::TransformSpace relativeTo = Ogre::Node::TS_LOCAL, 
			const Ogre::Vector3& localDirectionVector = Ogre::Vector3::NEGATIVE_UNIT_Z);

		void setDirection(Ogre::Real x, Ogre::Real y, Ogre::Real z, Ogre::Node::TransformSpace relativeTo = Ogre::Node::TS_LOCAL, 
			const Ogre::Vector3& localDirectionVector = Ogre::Vector3::NEGATIVE_UNIT_Z);

		void setFixedYawAxis( bool useFixed, const Ogre::Vector3& fixedAxis = Ogre::Vector3::UNIT_Y );

		float getRadius(void);
		Ogre::Vector3 getBoundingBoxSize(void);
		Ogre::AxisAlignedBox getBoundingBox(void);
		Ogre::AxisAlignedBox getWorldBoundingBox(void);


		SceneObject* getSceneObject()
		{
			return _sceneObject;
		}
		/*Select current game object, may do highlight or etc.
		@param selected Whether or not set the current object selected.
		*/
		virtual void selectObject(bool selected);

		//update
		virtual void update(float deltaT);

		/*Get current game object's name
		*/
		std::string getName();

		/*Set current game object's name
		*/
		void setName(std::string name);

		inline Ogre::SceneNode* GameObject::getSceneNode()
		{
			return _sceneNode;
		}

		bool isTerrain()
		{
			return _isTerrain;
		}

		bool isMesh()
		{
			return _isMesh;
		}

		bool isRoot()
		{
			return _isRoot;
		}

		int getComponentCount(){
			
			return 0;
		}

		Component* getComponent(int index){
			return 0;
		}

		Ogre::Vector3 getPosition();
		virtual Ogre::Vector3 getDerivedPosition();
		const Ogre::Quaternion &getOrientation();
		Ogre::Vector3 getScale();
		const Ogre::Vector3 &getWorldPosition() const;
		const Ogre::Quaternion &getWorldOrientation() const;

	protected:
		//init empty game object.
		void initEmpty();

		//add component impl
		void addMesh(MeshComponent* component);
		void addTransform(TransformComponent* component);

		//update game object owned components
		void updateComponents(float deltaT);
		//update children
		void updateChildren(float deltaT);
	protected:
		static MapList _list;
		SceneObject* _sceneObject;//owner of the gameobject
		GameObject* _parent;
		GameObjectVector _children;
		
		Component* _components[COMPONENT_TYPE_COUNT];
		Ogre::SceneNode* _sceneNode;//represent transform

		std::string _name;//game object name
		bool _selected;
		bool _isMesh;
		bool _isTerrain;
		bool _isRoot;//is special root game object.
		
		GameObjectType _gameObjectType;
	protected:
		friend class SceneObject;
		

	};
}

#endif
